/*
 * ClassTree.java
 * Created on Sep 1, 2004
 *
 */
package abdn.graph.growl.editor;

import java.awt.Color;
import java.awt.Component;
import java.util.*;
import javax.swing.*;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.*;

import abdn.graph.growl.GraphUtil;
import abdn.graph.ontobrowser.OBEdge;
import abdn.graph.ontobrowser.OBNode;
import abdn.graph.ontobrowser.OBObjectNode;

/**
 * ClassTree.java
 * @author Rich
 *
 */
public class ClassTree extends JTree
{
  ImageIcon classIco = new javax.swing.ImageIcon(getClass().getResource(
      "/abdn/graph/growl/images/Class.gif"));
  ClassTreeModel model;

  public ClassTree(Set classes, boolean multiple)
  {
    setModel(model = new ClassTreeModel(classes));
    getSelectionModel().setSelectionMode(multiple ? TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION : TreeSelectionModel.SINGLE_TREE_SELECTION);
    setIcons();
    setRootVisible(false);
    setShowsRootHandles(true);
    putClientProperty("JTree.lineStyle", "Angled");
  }

  private void setIcons()
  {
    ClassTreeCellRenderer renderer = new ClassTreeCellRenderer();
    renderer.setClosedIcon(classIco);
    renderer.setOpenIcon(classIco);
    renderer.setLeafIcon(classIco);
    setCellRenderer(renderer);
  }

  public OBObjectNode getSelection()
  {
    TreePath path = getSelectionPath();
    return getNodeOfPath(path);
  }

  public OBObjectNode getNodeOfPath(TreePath path)
  {
    if(path != null)
    {
      return ((ClassNode)path.getLastPathComponent()).getNode();
    }
    return null;
  }

  public void positionTo(OBObjectNode node)
  {
    TreePath path = model.pathToNode(node);
    if( path != null )
    {
      scrollPathToVisible(path);
      setSelectionPath(path);
    }
  }

  class ClassNode {
    Vector children;
    Vector childNodes = new Vector();

    /* (non-Javadoc)
     * @see abdn.graph.growl.ClassTree.ClassNode#childCount()
     */
    public int childCount() {
      return childNodes.size();
    }

    /* (non-Javadoc)
     * @see abdn.graph.growl.ClassTree.ClassNode#childAt(int)
     */
    public ClassNode childAt(int i) {
      ClassNode node = (ClassNode)childNodes.get(i);
      if( node == null ) {
        node = new GenericClassNode((OBObjectNode)children.get(i));
        childNodes.set(i, node);
      }
      return node;
    }

    /* (non-Javadoc)
     * @see abdn.graph.growl.ClassTree.ClassNode#indexOfChild(abdn.graph.growl.ClassTree.ClassNode)
     */
    public int indexOfChild(ClassNode n) {
      return childNodes.indexOf(n);
    }

    /* (non-Javadoc)
     * @see abdn.graph.growl.ClassTree.ClassNode#isLeaf()
     */
    public boolean isLeaf() {
      return childNodes.size() == 0;
    }

    public OBObjectNode getNode() {
      return null;
    }

    public ClassNode getNodeOfObjNode(OBObjectNode node) {
      int i = children.indexOf(node);
      if( i >= 0 ) {
        return childAt(i);
      }
      return null;
    }
  }

  class RootClassNode extends ClassNode {

    RootClassNode(Vector v) {
      children = v;
      //int max = children.size();
      for(int i = 0; i < children.size(); i++) {
        //System.out.println("RootNode: " + ( (OBObjectNode) children.get(i)).getName() );
        childNodes.add(null);
      }
    }

    public String toString() {
      return "";
    }
  }

  class GenericClassNode extends ClassNode {
    OBObjectNode node;

    GenericClassNode(OBObjectNode n) {
      node = n;
      Vector sub = EditorGUI.getSubVectClasses(node);
      //System.out.println("Sub to String(): " + sub.toString() );
      children = new Vector();
      for ( int i = 0; i < sub.size(); i++ ) {
        String nodeName = ((OBObjectNode)sub.get(i)).getName();
        //System.out.println("Node name: " + nodeName );
        if ( nodeName.equals("owl:thing") || nodeName.equals("thing") ){
          //if either do not display it
        } else {
          children.add(sub.get(i));
          childNodes.add(null);
        }
      }
    }

    public String toString() {
      return node.getLabel();
    }

    public OBObjectNode getNode() {
      return node;
    }
  }

  class ClassTreeModel implements TreeModel {
    private Vector treeModelListeners = new Vector();
    ClassNode root;

    ClassTreeModel(Set owlObjects) {
      Vector rootNodes = new Vector();
      if( owlObjects != null) {
        for (Iterator it = owlObjects.iterator(); it.hasNext();) {
          OBObjectNode obj = (OBObjectNode)it.next();
          //System.out.println("Root Node: " + obj.getName() );
          if( isRootNode(obj) ) {
            rootNodes.add(obj);
          }
        }
      }
      root = new RootClassNode(rootNodes);
    }

    private boolean isRootNode(OBObjectNode node) {
      return getFirstSuperClass(node) == null;
    }

    private OBObjectNode getFirstSuperClass(OBObjectNode node) {
      for(Iterator i = node.edges.iterator(); i.hasNext();) {
        OBEdge e = (OBEdge)i.next();
        if( e.from == node && e.edgeOrder == OBEdge.SUBCLASS_OF_EDGE && GraphUtil.isClass((OBNode)e.to) ) {
          return (OBObjectNode)e.to;
        }
      }
      return null;
    }

    /* (non-Javadoc)
    * @see javax.swing.tree.TreeModel#getRoot()
    */
    public Object getRoot()
    {
      return root;
    }

    /* (non-Javadoc)
    * @see javax.swing.tree.TreeModel#getChildCount(java.lang.Object)
    */
    public int getChildCount(Object o)
    {
      return ((ClassNode)o).childCount();
    }

    /* (non-Javadoc)
    * @see javax.swing.tree.TreeModel#isLeaf(java.lang.Object)
    */
    public boolean isLeaf(Object o) {
      return ((ClassNode)o).isLeaf();

    }

    /* (non-Javadoc)
    * @see javax.swing.tree.TreeModel#addTreeModelListener(javax.swing.event.TreeModelListener)
    */
    public void addTreeModelListener(TreeModelListener l) {
        treeModelListeners.addElement(l);
    }


    /* (non-Javadoc)
    * @see javax.swing.tree.TreeModel#removeTreeModelListener(javax.swing.event.TreeModelListener)
    */
    public void removeTreeModelListener(TreeModelListener l) {
        treeModelListeners.removeElement(l);
    }

    /* (non-Javadoc)
    * @see javax.swing.tree.TreeModel#getChild(java.lang.Object, int)
    */
    public Object getChild(Object o, int idx) {
      return ((ClassNode)o).childAt(idx);
    }

    /* (non-Javadoc)
    * @see javax.swing.tree.TreeModel#getIndexOfChild(java.lang.Object, java.lang.Object)
    */
    public int getIndexOfChild(Object o, Object child) {
      return ((ClassNode)o).indexOfChild((ClassNode)child);
    }

    /* (non-Javadoc)
    * @see javax.swing.tree.TreeModel#valueForPathChanged(javax.swing.tree.TreePath, java.lang.Object)
    */
    public void valueForPathChanged(TreePath arg0, Object arg1) {
      // TODO Auto-generated method stub

    }

    public TreePath pathToNode(OBObjectNode node) {
      Vector reverse = new Vector();
      while( node != null ) {
        reverse.add(node);
        node = getFirstSuperClass(node);
      }
      int i, max = reverse.size();
      Object[] path = new Object[max + 1];
      path[0] = root;
      for( i = 0; i < max; i++ ) {
        path[i + 1] = ((ClassNode)path[i]).getNodeOfObjNode((OBObjectNode)reverse.get(max - i - 1));
      }
      return new TreePath(path);
    }

  }

  class ClassTreeCellRenderer extends DefaultTreeCellRenderer
  {
    public Component getTreeCellRendererComponent(
                          JTree tree,
                          Object value,
                          boolean sel,
                          boolean expanded,
                          boolean leaf,
                          int row,
                          boolean hasFocus) {

      Component c = super.getTreeCellRendererComponent(
                        tree, value, sel,
                        expanded, leaf, row,
                        hasFocus);
     /*  if( ((ClassNode)value).getNode().isHiden )
      {
        c.setForeground( sel ? Color.lightGray : Color.gray );
      }*/
      return c;
    }

  }

}